﻿//Copyright (c) 2010, Andreas Grünwald
//All rights reserved.

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using Slf;
using yaTDL.Core.IO;
using yaTDL.Core.Properties;
using yaTDL.Extensions;
using yaTDL.Core.MVVM;

namespace yaTDL.Core.Toodledo
{
    public class ToodledoSyncServiceV2: Service
    {

        static ApplicationSettings Settings = ApplicationSettings.Settings;

        /// <summary>
        /// Initializes a new instance of ToodledoSyncService.
        /// </summary>
        public ToodledoSyncServiceV2()
        {
            setTimer();
            timer.Enabled = Settings.Toodledo_EnableSync;

            Settings.PropertyChanged += new PropertyChangedEventHandler(Settings_PropertyChanged);

            toodledoClient.ErrorOccurred += new EventHandler<ErrorEventArgsV2>(toodledoClient_ErrorOccured);

            apiKey = Settings.Toodledo_APIKey;            
        }



        /// <summary>
        /// A event that will be raised if conflicting changes are found during sync.
        /// </summary>
        public event EventHandler<SyncConflictEventArgs> SyncConflictFound;



        /// <summary>
        /// The Logger used to log the synchronisations.
        /// </summary>
        ILogger syncLogger = LoggerService.GetLogger("ToodledoSync (v2)");

        /// <summary>
        /// The instance of ToodledoClient to interact with the Toodledo API.
        /// </summary>
        ToodledoClientV2 toodledoClient = new ToodledoClientV2();


        ToodledoAPIKey _apiKey = new ToodledoAPIKey();

        /// <summary>
        /// The currently used APIKey necessary for all methos of ToodledoClient.
        /// </summary>
        ToodledoAPIKey apiKey
        {
            get { return _apiKey; }
            set
            {
                if (value != _apiKey)
                {
                    _apiKey = value;
                    Settings.Toodledo_APIKey = _apiKey;                    
                    Settings.Save("Toodledo_APIKey");
                }
            }
        }

        /// <summary>
        /// The currently used ToodledoAccountInfo.
        /// </summary>
        ToodledoAccountInfoV2 accountInfo = new ToodledoAccountInfoV2();

        /// <summary>
        /// The instance of XMLFileaccess used to read/write cached data
        /// </summary>
        XMLFileHandler xmlFileaccess = new XMLFileHandler();

        /// <summary>
        /// Indicates whether there is currently a sync in progress; sync() will exit if true.
        /// </summary>
        static bool syncRunning = false;

        /// <summary>
        /// Stores whether there was a error raised by toodledoClient. If set to true, a Sync will end prematurely.
        /// </summary>
        bool errorOccurred = false;

        ErrorEventArgsV2 lastError = null;


        /// <summary>
        /// The Date and Time of the last synchorinsation.
        /// </summary>
        private DateTime lastSync { get { return Settings.Toodledo_LastSync; } }
     
        /// <summary>
        /// The Name of the file that stores the cached folder-list from the time of the last sync.
        /// </summary>
        private static string folderCacheLastSyncFileName { get { return Path.Combine(XMLFileHandler.DefaultDirectory, "Sync_folderCache.xml"); } }



        /// <summary>
        /// Executes the Service's task.
        /// </summary>
        protected override void DoAction()
        {
            sync();
        }

        /// <summary>
        /// Sets the timer that will start sync based on Settings.Default.Toodledo_SyncInterval.
        /// </summary>
        private void setTimer()
        {
            bool isEnabled = timer.Enabled;

            timer.Enabled = false;

            if ((DateTime.Now - Settings.Toodledo_LastSync).TotalMilliseconds > Settings.Toodledo_SyncInterval.TotalMilliseconds)
            {
                timer.Interval = new TimeSpan(0, 1, 0).TotalMilliseconds;
            }
            else
            {
                timer.Interval = Settings.Toodledo_SyncInterval.TotalMilliseconds;
            }

            timer.Enabled = isEnabled;
        }

        /// <summary>
        /// Listens for changes in the Settings and adjustes ToodledoSyncService if necessary.
        /// </summary>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="e">The System.ComponentModel.PropertyChangedEventArgs containing more information about the event.</param>
        private void Settings_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Toodledo_SyncInterval" || e.PropertyName == "Toodledo_LastSync" || e.PropertyName == "Toodledo_EnableSync")
            {
                setTimer();
            }
            if (e.PropertyName == "Toodledo_EnableSync")
            {
                timer.Enabled = Settings.Toodledo_EnableSync;
            }
        }

        /// <summary>
        /// Handles the ToodledoClient.ErrorOccured event. It will be logged and running syncs will be stopped.
        /// </summary>
        /// <param name="sender">The sender of the event.</param>
        /// <param name="e">EventArgs containing mor information about the error.</param>
        void toodledoClient_ErrorOccured(object sender, ErrorEventArgsV2 e)
        {
            errorOccurred = true;                                                        //will stop running syncs.
            lastError = e;

            syncLogger.Warn("An Error occured in ToodledoClient: {0}", e.ToString());   //logs the errror in the sync-log.
        }
        


        /// <summary>
        /// Sync all local data with Toodledo.
        /// </summary>
        private void sync()
        {

            //Check if sync is even enabled and if a sync is currently in progess
            if (!Settings.Toodledo_EnableSync || syncRunning)
                return;

            timer.Stop();


            errorOccurred = false;                                  //make sure the value of errorOccurred is false. If it is set to true, the Syncing might exit prematurely.

            syncLogger.Info("Sync started at {0}", DateTime.Now);


            if (String.IsNullOrEmpty(apiKey.Key) || apiKey.IsExpired)  //checks if there is a APIKey and if it is still valid
            {
                //if the APIKey cannot be used any more, a new one will be requested.

                //check if there is a UserId and Password stored in Settings
                if (!Settings.Toodledo_UserId.IsNullOrEmpty() && !Settings.Toodledo_Password.IsNullOrEmpty())
                {
                    syncLogger.Info("Requesting SessionToken");
                    string sessionToken = toodledoClient.GetSessionToken(Settings.Toodledo_UserId.Unwrap());
                    
                    syncLogger.Info("Generating Key");
                    apiKey = toodledoClient.GetKey(sessionToken, Settings.Toodledo_Password);

                    if (errorOccurred) { logExitSync(); return; }
                }
                else
                { if (errorOccurred) { logExitSync(); return; } }
            }


            accountInfo = toodledoClient.GetAccountInfo(apiKey.Key);

            if (errorOccurred && !lastError.Handled)
            {
                switch (lastError.ErrorCode)
                {
                    case 2:
                        apiKey = new ToodledoAPIKey();
                        syncLogger.Warn("Key was invalid and has been deleted. Sync will be exited. Retry later.");
                        lastError.Handled = false;
                        return;
                    default:
                        logExitSync();
                        return;
                }
            }

            


            //syncs Projects/Folders   
            syncFolders();

            if (errorOccurred && !lastError.Handled) { logExitSync(); return; }


            //syncs Tasks
            syncTasks();        
     

            Settings.Toodledo_LastSync = DateTime.Now;      //saves the Date and Time of the Sync
            Settings.Save("Toodledo_LastSync");

            syncLogger.Info("Sync Completed at {0}", DateTime.Now);

            setTimer();
            timer.Enabled = Settings.Toodledo_EnableSync;
            

        }

        /// <summary>
        /// Syncs local Projects with Folders on Toodledo.
        /// </summary>
        private void syncFolders()
        {

            syncLogger.Info("Syncing Folders");

            //search for folders added locally and add them to Toodledo

            List<Change> changes_addedFolders = (from change in TaskStore.GetChanges()
                                                 where change.ChangedItemType == typeof(Project)
                                                 && change.Kind == ChangeKind.Added
                                                 && change.ChangeTime >= lastSync
                                                 && !change.HandledInSync
                                                 && TaskStore.ProjectExists(change.ItemId)
                                                 select change).ToList<Change>();

            List<Project> addedFolders = (from change in changes_addedFolders
                                          select TaskStore.GetProject(change.ItemId)).ToList<Project>();
            
            syncLogger.Info("{0} Folders have been added locally", addedFolders.Count);

            foreach (Project p in addedFolders)
            {
                bool sucessful = toodledoClient.AddFolder(apiKey.Key, p);

                if (sucessful)
                {
                    syncLogger.Info("Sucessfully added Folder, Id: {0}", p.Id);
                    changes_addedFolders.First(x => x.ItemId == p.Id).HandledInSync = true;
                }


                //tries to handle occured errors

                if (errorOccurred && !lastError.Handled)
                {
                    switch (lastError.ErrorCode)
                    {
                            //The error with the code 5 occurs, when there already is a folder with the name of the folder that is being added
                            //to resolve the error, the folders will be merged by changing the Id of the local folder that is to be added to the Id of the folder that already exists online
                        case 5:
                            var matchingfolder = from folder in toodledoClient.GetFolders(apiKey.Key)
                                                 where folder.Name == p.Name
                                                 select folder;

                            if (matchingfolder.Any())
                            {
                                p.Id = matchingfolder.First().Id;

                                syncLogger.Info("Handled Error, changed Id of local Project to {0}", p.Id);

                                lastError.Handled = true;
                            }

                            break;

                        default:
                            logExitSync();
                            return;
                    }
                }

            }


            //search for folders deleted locally and delete them on Toodledo

            int i = -1;
            List<int> foldersDeletedLocally = (from id in TaskStore.GetDeletedProjects(lastSync)
                                              where Int32.TryParse(id, out i)
                                              select i).ToList<int>();

            syncLogger.Info("{0} Folders have been deleted locally", foldersDeletedLocally.Count);

            foreach (int id in foldersDeletedLocally)
            {
                toodledoClient.DeleteFolder(apiKey.Key, id);

                if (errorOccurred && lastError.Handled == false) 
                {
                    switch (lastError.ErrorCode)
                    {
                        //ErrorCode 4 indicates that the Folder that was to be deleted does not exist.
                        //In this case the error can just be ignored, as the folder should be deleted anway.
                        case 4:
                            lastError.Handled = true;
                            break;
                        default:
                            logExitSync(); 
                            return; 
                    }
                    
                }
            }
     

            //sync Folders modified online

            Dictionary<string, Project> foldersOnline = new Dictionary<string, Project>();

            if (accountInfo.LastFolderEdit > lastSync)
            {
                foldersOnline = toodledoClient.GetFolders(apiKey.Key).ToDictionary<Project, string>(x => x.Id);

                //search for Folders that only exist online and store it locally

                List<Project> foldersOnlyOnline = (from project in foldersOnline.Values
                                                   where !TaskStore.ProjectExists(project.Id)
                                                   select project).ToList<Project>();
                
                syncLogger.Info("Found {0} Folders that only exist online. Storing them locally.", foldersOnlyOnline.Count);
                
                foreach (Project p in foldersOnlyOnline)
                {
                    TaskStore.AddProject(p);
                }

                //search for Folders missing online but stored locally and delete them

                List<string> foldersMissingOnline = (from project in TaskStore.GetProjects()
                                                     where !foldersOnline.ContainsKey(project.Id)
                                                     select project.Id).ToList<string>();

                syncLogger.Info("Found {0} Folders missing online. Deleteing them locally.", foldersMissingOnline.Count);

                foreach (String str in foldersMissingOnline)
                {
                    TaskStore.RemoveProject(str);
                }

                //search for folders that exists both locally and online and merge them if necessary

                List<Project> foldersRemaining = (from project in foldersOnline.Values
                                                  where TaskStore.ProjectExists(project.Id)
                                                  select project).ToList<Project>();

                syncLogger.Info("{0} Folders exist both online and offline", foldersRemaining.Count);

                foreach (Project p in foldersRemaining)
                {
                    Project p_localCopy = TaskStore.GetProject(p.Id);
                    
                    //determine whether there is any difference between the local copy and the Folder stored online

                    Collection<PropertyChange> diff = p.Diff(p_localCopy);

                    //as the Order Property cannot be set via the API, differences between local and online values can be ignored
                    List<PropertyChange> ignorableChanges = (from pChange in diff
                                                             where pChange.PropertyName == "Order"
                                                             || pChange.PropertyName == "UserId"
                                                             select pChange).ToList<PropertyChange>();

                    foreach (PropertyChange pChange in ignorableChanges)
                    {
                        switch (pChange.PropertyName)
                        {
                            case "Order":
                                diff.Remove(pChange);
                                break;
                            case "UserId":
                                p_localCopy.UserId = p.UserId;
                                diff.Remove(pChange);
                                break;
                        }
                    }                    


                    //if the only remaing difference is LastEdited, it can also be ignored

                    if (diff.Count == 1)
                    {
                        if (diff.First().PropertyName == "LastEdited")
                        {
                            diff.RemoveAt(0);
                        }
                    }

                    if (diff.Any())
                    {                        
                        syncLogger.Info("Project/Folder, Id: {0}: Found differences between local and online copy", p.Id);

                        //if the local copy of the Folder has not been changed since the last sync, 
                        //it's Properties will just be overwritten with the values from the online copy
                        if (p_localCopy.LastEdited < lastSync)
                        {
                            syncLogger.Info("{0}: Local Copy has not been modified since last sync. Overwriting properties with values from online copy", p_localCopy.ToShortString());

                            p_localCopy.ApplyProperties(p);
                        }
                        else
                        {
                            //if the Folder has been editet locally, it can not be determined, which data is to be used
                            //The user will be asked to resolve the conflict.

                            List<object> items = new List<object>();
                            items.Add(p_localCopy);
                            items.Add(p);

                            SyncConflictViewModel viewModel = new SyncConflictViewModel(items);
                            ViewManager.ShowView(viewModel);

                            if (!ViewManager.HasRegisteredView(typeof(SyncConflictViewModel)))
                            {
                                viewModel.SelectedItem = p;
                            }

                            //The data from the merged Project will be applied to both the local and the online copy

                            Project p_resolved = viewModel.SelectedItem as Project;

                            syncLogger.Info("Merged data from both sources, updating local copy");

                            p_localCopy.ApplyProperties(p_resolved);

                            p.ApplyProperties(p_resolved);

                            syncLogger.Info("Updating Project/Folder on Toodledo");

                            toodledoClient.UpdateFolder(apiKey.Key,p);

                            if (errorOccurred && !lastError.Handled) { logExitSync(); return; }
                        }
                    }
                    else
                    {
                        syncLogger.Info("No difference found for {0}", p.ToShortString());
                    }
                }
            }
            else
            {
                syncLogger.Info("No Folders have been edited online");

                //search for folders modified only locally

                List<Project> foldersModifiedLocallyOnly = (from change in TaskStore.GetChanges()
                                                            where change.ChangedItemType == typeof(Project)
                                                            && change.Kind == ChangeKind.Modified
                                                            && change.ChangeTime >= lastSync
                                                            && change.PropertyName != "Id"
                                                            && TaskStore.ProjectExists(change.ItemId)
                                                            select TaskStore.GetProject(change.ItemId)).ToList<Project>();

                syncLogger.Info("{0} Folders have been edited locally", foldersModifiedLocallyOnly.Count);

                foreach (Project p in foldersModifiedLocallyOnly)
                {
                    toodledoClient.UpdateFolder(apiKey.Key, p);

                    if (errorOccurred && !lastError.Handled) { logExitSync(); return; }
                }
            }

        }

        /// <summary>
        /// Syncs local Tasks with Toodledo.
        /// </summary>
        private void syncTasks()
        {
            syncLogger.Info("Syncing Tasks");


            //search for Tasks added locally and add them to Toodledo

            List<Change> changes_addedLocally = (from change in TaskStore.GetChanges()
                                            where change.ChangedItemType == typeof(Task)
                                            && change.Kind == ChangeKind.Added
                                            && change.ChangeTime >= lastSync
                                            && TaskStore.TaskExists(change.ItemId)
                                            && !change.HandledInSync
                                            select change).ToList<Change>();

            List<Task> tasksAddedLocally = (from change in changes_addedLocally
                                            select TaskStore.GetTask(change.ItemId)).ToList<Task>();


            syncLogger.Info("{0} Tasks have been added locally, uploading them to Toodledo", tasksAddedLocally.Count);

            if (tasksAddedLocally.Any())
            {
                bool successful = toodledoClient.AddTasks(apiKey.Key, tasksAddedLocally);

                if (successful)
                {
                    syncLogger.Info("Sucessfully uploaded Tasks to Toodledo");

                    foreach (Change c in changes_addedLocally)
                    {
                        c.HandledInSync = true;
                    }
                }
                else
                { syncLogger.Error("Could not upload Tasks to Toodledo"); }

            }


            

            //search for Tasks deleted locally and delete them on Toodledo

            int i = -1;
            List<int> tasksToBeDeletedOnline = (from id in TaskStore.GetDeletedTasks(lastSync)
                                                where Int32.TryParse(id, out i)
                                                select i).ToList<int>();

            syncLogger.Info("{0} Tasks have been deleted locally", tasksToBeDeletedOnline.Count);

            if (tasksToBeDeletedOnline.Any())
            {
                toodledoClient.DeleteTasks(apiKey.Key, tasksToBeDeletedOnline);
            }


            
            //sync Tasks modified online

            Dictionary<String, Task> tasksOnline = new Dictionary<String, Task>();

            if (accountInfo.LastTaskEdit > lastSync)
            {
                tasksOnline = toodledoClient.GetTasks(apiKey.Key, new List<Parameter>() { new Parameter() { Name = "modafter", Value = lastSync } }).ToDictionary<Task, String>(x => x.Id);
                
                //determine which Tasks have been added online and store them locally

                List<Task> tasksAddedOnline = (from task in tasksOnline.Values
                                               where !TaskStore.TaskExists(task.Id)
                                               select task).ToList<Task>();

                syncLogger.Info("{0} Tasks have been modified or added online", tasksAddedOnline.Count);

                foreach (Task t in tasksAddedOnline)
                {
                    syncLogger.Info("Adding to local data. {0}", t.ToShortString());
                    TaskStore.AddTask(t);
                }


                //determine which Tasks have been modified online and are already stored locally

                List<Task> tasksModifiedOnline = (from task in tasksOnline.Values
                                                  where TaskStore.TaskExists(task.Id)
                                                  select task).ToList<Task>();

                List<Task> tasksToBeUpdatedOnline = new List<Task>();

                foreach (Task t in tasksModifiedOnline)
                {
                    Task t_localCopy = TaskStore.GetTask(t.Id);

                    //check if the task has been modified locally, too.

                    Collection<PropertyChange> diff = t.Diff(t_localCopy);

                    //search for differences that can be ignored
                    //if only the time paste of DueDate differs, it can be ignored, as both yaTDL and Toodledo only display the date without time

                    List<PropertyChange> ignorableChanges = (from pChange in diff
                                                             where (pChange.PropertyName == "DueDate"
                                                             && ((DateTime)pChange.Value1).Date == ((DateTime)pChange.Value2).Date)
                                                             || pChange.PropertyName == "UserId"
                                                             || pChange.PropertyName == "Indent"
                                                             || pChange.PropertyName == "Collapsed"
                                                             || pChange.PropertyName == "Order"
                                                             || (pChange.PropertyName == "Content" && (pChange.Value1 as string).Trim() == (pChange.Value2 as string).Trim())
                                                             select pChange).ToList<PropertyChange>();

                    foreach (PropertyChange pChange in ignorableChanges)    
                    {
                        if (pChange.PropertyName == "DueDate")              //Differences of the Date Property can be ignored if they only differ in their time component (see LINQ query above)
                        {
                            t_localCopy.DueDate = t.DueDate;
                        }
                        else if (pChange.PropertyName == "UserId")          //Differences of UserId, Indent, Collapsed and Order can also be ignored, as they are not used by either Toodledo or yaTDL
                        {
                            t_localCopy.UserId = t.UserId;                  //For all Differences that can be ignored, the local copy will be overwritten with the data downloaded from Toodledo
                        }
                        else if (pChange.PropertyName == "Indent")
                        {
                            t_localCopy.Indent = t.Indent;
                        }
                        else if (pChange.PropertyName == "Collapsed")
                        {
                            t_localCopy.Collapsed = t.Collapsed;
                        }
                        else if (pChange.PropertyName == "Order")
                        {
                            t_localCopy.Order = t.Order;
                        }
                        else if (pChange.PropertyName == "Content")         //Differenes of the Content Property can be ignored if it only differs by spaces at the end or the beginning
                        {
                            t_localCopy.Content = t.Content;
                        }

                        diff.Remove(pChange);
                    }

                    if (t_localCopy.LastEdited > lastSync && diff.Any())
                    {
                        //merge data, if Task has been modified both online and locally

                        syncLogger.Info("Task, Id: {0} has been modified both locally and online", t.Id);

                        List<object> items = new List<object>();
                        items.Add(t);
                        items.Add(t_localCopy);


                        SyncConflictViewModel syncConflictViewModel = new SyncConflictViewModel(items);
                        ViewManager.ShowView(syncConflictViewModel);

                        if (!ViewManager.HasRegisteredView(typeof(SyncConflictViewModel)))
                        {
                            if (t_localCopy.LastEdited >= t.LastEdited)
                            {
                                syncConflictViewModel.SelectedItem = t_localCopy;
                            }
                            else
                            { syncConflictViewModel.SelectedItem = t; }
                        }

                        Task t_resolved = syncConflictViewModel.SelectedItem as Task;

                        syncLogger.Info("Merged data from both Tasks, updating local data");

                        //update local copy with merged data
                        t_localCopy.ApplyProperties(t_resolved);
                        t.ApplyProperties(t_resolved);

                        //Add Task to the list of Tasks that will be updated online
                        tasksToBeUpdatedOnline.Add(t);
                    }
                    else
                    {
                        syncLogger.Info("Updating local copy of Task, Id: {0}", t.Id);

                        t_localCopy.ApplyProperties(t);
                    }
                }

                //updating Tasks on Toodledo

                syncLogger.Info("Updating {0} Tasks on Toodledo", tasksToBeUpdatedOnline.Count);

                if (tasksToBeUpdatedOnline.Any())
                {
                    toodledoClient.UpdateTasks(apiKey.Key, tasksToBeUpdatedOnline);
                }

            }
            else
            {
                syncLogger.Info("No Tasks modified online since last Sync");
            }


            //check if any tasks have been deleted online since the last sync and delete them locally

            if (accountInfo.LastTaskDelete > lastSync)
            {
                List<string> tasksDeletedOnline = toodledoClient.GetDeletedTasks(apiKey.Key, lastSync).ToList<string>();

                syncLogger.Info("{0} Tasks have been deleted online", tasksDeletedOnline.Count);

                foreach (string s in tasksDeletedOnline)
                {
                    if (TaskStore.TaskExists(s))
                    {
                        syncLogger.Info("Deleting locally. {0}", TaskStore.GetTask(s).ToShortString());
                        TaskStore.RemoveTask(s);
                    }
                    else
                    {
                        syncLogger.Warn("Could not find Task, Id: {0} locally (was deleted online). Will be ignored.", s);
                    }
                }
            }
            else
            {
                syncLogger.Info("No Tasks deleted online since last Sync");
            }

            //search for Tasks edited locally only and update them on Toodledo

            List<Task> tasksModifiedOnlyLocally = (from change in TaskStore.GetChanges(true)
                                                   where change.ChangedItemType == typeof(Task)
                                                   && change.Kind == ChangeKind.Modified
                                                   && !tasksOnline.ContainsKey(change.ItemId)
                                                   && TaskStore.TaskExists(change.ItemId)
                                                   orderby change.ItemId
                                                   select TaskStore.GetTask(change.ItemId)).ToList<Task>();

            //remove duplicate changes
            //int maxIndex = tasksModifiedOnlyLocally.Count - 1;            

            
            //for (int i2 = 0; i2 < maxIndex-1; i2++)
            //{
            //    if (tasksModifiedOnlyLocally[i2].Id == tasksModifiedOnlyLocally[i2 + 1].Id)
            //    {
            //        tasksModifiedOnlyLocally.RemoveAt(i2 + 1);
            //        maxIndex -= 1;
            //    }
            //}


            syncLogger.Info("{0} Tasks have been modified locally.", tasksModifiedOnlyLocally.Count);

            if (tasksModifiedOnlyLocally.Any())
            {
                syncLogger.Info("Updating {0} Tasks", tasksModifiedOnlyLocally.Count);
                toodledoClient.UpdateTasks(apiKey.Key, tasksModifiedOnlyLocally);
            }

        }


        private static bool PropertyChangeIsLastEdited(PropertyChange p)
        {
            return p.PropertyName == "LastEdited" ? true : false;
        }


        /// <summary>
        /// Logs that sync has been exited before being completed.
        /// </summary>
        private void logExitSync()
        {
            syncLogger.Error("Sync exited before it was completed");
        }

        /// <summary>
        /// Raises a new SyncConflictFound event.
        /// </summary>
        /// <param name="e">The SyncConflictEventArgs for this event.</param>
        private void OnSyncConflictFound(SyncConflictEventArgs e)
        {
            if (SyncConflictFound != null)
            {
                SyncConflictFound(this, e);
            }
        }    
    }
}
